Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\dynamic\src\buffer\view.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use std::cell::{Cell, UnsafeCell};
30
use std::fmt::{Debug, Display};
31
use std::io::Write;
32
use std::ops::{Index, IndexMut};
33
use std::rc::Rc;
34
use crate::buffer::buffer::Buffer;
35
use crate::component::{Component, util::DiscoverTool};
36
use crate::field::primitive::{PrimitiveType, PrimitiveValue, PrimitiveValueMut};
37
use bp3d_debug::trace;
38
use crate::buffer::unsafe_buffer::UnsafeBuffer;
39
40
#[derive(Debug)]
41
pub struct Location {
42
    pub fixed: bool,
43
    pub offset: isize,
44
    pub size: usize,
45
}
46
47
#[derive(Debug)]
48
pub(super) struct PathComponent {
49
    pub(super) name: String,
50
    pub(super) index: Cell<isize>,
51
    // Unfortunately RefCell is unusable because if RefCell then loops are forbidden.
52
    //TODO: Try to find better than UnsafeCell.
53
    pub(super) parent: UnsafeCell<Option<Rc<PathComponent>>>
54
}
55
56
pub struct BufferView<'a> {
57
    pub(super) path_component: Rc<PathComponent>,
58
    pub(super) buffer: Buffer<'a>,
59
    pub(super) children: Vec<BufferView<'a>>,
60
    pub(super) location: Location,
61
    pub(super) component: Option<Box<dyn Component>>,
62
    pub(super) items: Option<Vec<BufferView<'a>>>,
63
    pub(super) primitive: Option<Box<dyn PrimitiveType>>,
64
}
65
66
impl Debug for BufferView<'_> {
67
5
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68
5
        if self.primitive.is_none() {
  Branch (68:12): [True: 5, False: 0]
  Branch (68:12): [True: 0, False: 0]
69
5
            write!(f, "BufferView {{ name: {}, location: {:?}, children: {:?} }}", self.path_component.name, self.location, self.children)
70
        } else {
71
0
            write!(f, "BufferView {{ name: {}, location: {:?}, children: {:?}, primitive }}", self.path_component.name, self.location, self.children)
72
        }
73
5
    }
74
}
75
76
impl Display for BufferView<'_> {
77
12
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78
12
        let path_max_width = self.get_path_max_width();
79
12
        let hex_max_width = self.get_hex_max_width();
80
12
        writeln!(f, "|-{:-^path_max_width$}-|-{:-^6}-|-{:-^6}-|-{:-^hex_max_width$}-|-{:-^10}-|", "", "", "", "", "")
?0
;
81
12
        writeln!(f, "| {: ^path_max_width$} | {: ^6} | {: ^6} | {: ^hex_max_width$} | {: ^10} |", "Path", "Offset", "Size", "Hex", "Value")
?0
;
82
12
        writeln!(f, "|-{:-^path_max_width$}-|-{:-^6}-|-{:-^6}-|-{:-^hex_max_width$}-|-{:-^10}-|", "", "", "", "", "")
?0
;
83
12
        self.dump_children(f, path_max_width, hex_max_width)
?0
;
84
12
        Ok(())
85
12
    }
86
}
87
88
impl<'a> BufferView<'a> {
89
60
    fn get_path_max_width(&self) -> usize {
90
60
        let mut path_max_width = 0;
91
108
        for 
child48
in &self.children {
92
48
            let len = child.get_path().len();
93
48
            if len > path_max_width {
  Branch (93:16): [True: 2, False: 1]
  Branch (93:16): [True: 17, False: 28]
94
19
                path_max_width = len;
95
29
            }
96
48
            let other_len = child.get_path_max_width();
97
48
            if other_len > path_max_width {
  Branch (97:16): [True: 1, False: 2]
  Branch (97:16): [True: 6, False: 39]
98
7
                path_max_width = other_len;
99
41
            }
100
        }
101
60
        path_max_width
102
60
    }
103
104
23
    fn get_hex_max_width(&self) -> usize {
105
23
        if self.buffer.flat.get() { //If the buffer is flat then hex max width is by definition the
  Branch (105:12): [True: 1, False: 0]
  Branch (105:12): [True: 8, False: 14]
106
            // master buffer len.
107
9
            return self.buffer.len() * 3;
108
14
        }
109
14
        let mut hex_max_width = 0;
110
25
        for 
child11
in &self.children {
111
11
            trace!({len=child.buffer.len()} {offset=child.buffer.offset}, "get_hex_max_width");
112
11
            let len = if child.buffer.len() == 0 {
  Branch (112:26): [True: 0, False: 0]
  Branch (112:26): [True: 3, False: 8]
113
3
                3
114
            } else {
115
8
                (child.buffer.len() + child.buffer.offset) * 3
116
            };
117
11
            if len > hex_max_width {
  Branch (117:16): [True: 0, False: 0]
  Branch (117:16): [True: 5, False: 6]
118
5
                hex_max_width = len;
119
6
            }
120
11
            let other_len = child.get_hex_max_width();
121
11
            if other_len > hex_max_width {
  Branch (121:16): [True: 0, False: 0]
  Branch (121:16): [True: 0, False: 11]
122
0
                hex_max_width = other_len;
123
11
            }
124
        }
125
14
        hex_max_width
126
23
    }
127
128
60
    fn dump_children(&self, f: &mut std::fmt::Formatter<'_>, path_max_width: usize, hex_max_width: usize) -> std::fmt::Result {
129
108
        for 
child48
in &self.children {
130
48
            let value = child.get_primitive().map(|v| 
v.get()22
.
to_string22
()).unwrap_or("####".into());
131
48
            let bytes = format!("{:02X?}", child.buffer.as_bytes()).replace(",", "");
132
48
            let bytes = &bytes[1..bytes.len() - 1];
133
48
            let mut padding = String::from("");
134
382
            for _ in 0..
child.buffer.offset48
{
135
382
                padding += ".. ";
136
382
            }
137
48
            writeln!(f, "| {: <path_max_width$} | {: ^6} | {: ^6} | {: <hex_max_width$} | {: ^10} |", child.get_path(), child.buffer.offset, child.buffer.len(), padding + bytes, value)
?0
;
138
48
            child.dump_children(f, path_max_width, hex_max_width)
?0
;
139
        }
140
60
        Ok(())
141
60
    }
142
143
58
    pub fn get_primitive(&self) -> Option<PrimitiveValue> {
144
58
        self.primitive.as_ref().map(|v| 
PrimitiveValue::new32
(
self.buffer.as_bytes()32
,
&**v32
))
145
58
    }
146
147
11
    pub fn get_primitive_mut(&mut self) -> Option<PrimitiveValueMut> {
148
11
        self.primitive.as_ref().map(|v| PrimitiveValueMut::new(self.buffer.as_bytes_mut(), &**v))
149
11
    }
150
151
16
    pub fn location_mut(&mut self) -> &mut Location {
152
16
        &mut self.location
153
16
    }
154
155
0
    pub fn location(&self) -> &Location {
156
0
        &self.location
157
0
    }
158
159
84
    pub fn buffer(&self) -> &Buffer<'a> {
160
84
        &self.buffer
161
84
    }
162
163
18
    pub fn buffer_mut(&mut self) -> &mut Buffer<'a> {
164
18
        &mut self.buffer
165
18
    }
166
167
18
    pub fn get(&self, path: &str) -> Option<&BufferView<'a>> {
168
18
        let split = path.split(".");
169
18
        let mut view = self;
170
47
        for 
name30
in split {
171
30
            let id = name.find('[');
172
30
            let name = id.map(|v| &
name[..v]1
).unwrap_or(name);
173
50
            view = 
view.children.iter()30
.
find30
(|child| child.path_component.name == name)
?0
;
174
30
            if let Some(
id1
) = id {
  Branch (174:20): [True: 1, False: 15]
  Branch (174:20): [True: 0, False: 14]
175
1
                view = view.items.as_ref()?.
get0
(
id0
)
?0
;
176
29
            }
177
        }
178
17
        Some(view)
179
18
    }
180
181
0
    pub fn add_item(&mut self, mut view: BufferView<'a>) {
182
0
        let mut items = self.items.take().unwrap_or_default();
183
0
        view.buffer.flat = self.buffer.flat.clone();
184
0
        for child in view.iter_mut() {
185
0
            child.buffer.flat = self.buffer.flat.clone();
186
0
        }
187
0
        *unsafe { &mut *view.path_component.parent.get() } = Some(self.path_component.clone());
188
0
        view.path_component.index.set((items.len() - 1) as _);
189
0
        items.push(view);
190
0
        self.items = Some(items);
191
0
        self.buffer.flat.set(false);
192
0
    }
193
194
0
    pub fn remove_item(&mut self, index: usize) {
195
0
        if let Some(items) = &mut self.items {
  Branch (195:16): [Folded - Ignored]
  Branch (195:16): [True: 0, False: 0]
196
0
            items.remove(index);
197
0
            for (i, v) in items.iter_mut().enumerate() {
198
0
                v.path_component.index.set(i as _);
199
0
            }
200
0
            self.buffer.flat.set(false);
201
0
        }
202
0
    }
203
204
1
    pub fn add_child(&mut self, mut view: BufferView<'a>) {
205
1
        view.buffer.flat = self.buffer.flat.clone();
206
3
        for child in 
view1
.
iter_mut1
() {
207
3
            child.buffer.flat = self.buffer.flat.clone();
208
3
        }
209
1
        *unsafe { &mut *view.path_component.parent.get() } = Some(self.path_component.clone());
210
1
        self.children.push(view);
211
1
        self.buffer.flat.set(false);
212
1
    }
213
214
0
    pub fn clear(&mut self) {
215
0
        self.children.clear();
216
0
        self.buffer.flat.set(false);
217
0
    }
218
219
16
    pub fn get_mut(&mut self, path: &str) -> Option<&mut BufferView<'a>> {
220
16
        let split = path.split(".");
221
16
        let mut view = self;
222
38
        for 
name22
in split {
223
22
            let id = name.find('[');
224
22
            let name = id.map(|v| &
name[..v]0
).unwrap_or(name);
225
42
            view = 
view.children.iter_mut()22
.
find22
(|child| child.path_component.name == name)
?0
;
226
22
            if let Some(
id0
) = id {
  Branch (226:20): [True: 0, False: 4]
  Branch (226:20): [True: 0, False: 18]
227
0
                view = view.items.as_mut()?.get_mut(id)?;
228
22
            }
229
        }
230
16
        Some(view)
231
16
    }
232
233
6
    pub fn is_empty(&self) -> bool {
234
6
        self.children.is_empty()
235
6
    }
236
237
0
    pub fn len(&self) -> usize {
238
0
        self.children.len()
239
0
    }
240
241
0
    pub fn iter(&self) -> impl Iterator<Item=&BufferView<'a>> {
242
0
        self.children.iter()
243
0
    }
244
245
3
    pub fn iter_mut(&mut self) -> impl Iterator<Item=&mut BufferView<'a>> {
246
3
        self.children.iter_mut()
247
3
    }
248
249
1
    pub fn read_copy(&mut self, bytes: &[u8]) -> bp3d_proto::message::Result<usize> {
250
1
        self.buffer.copy_from(bytes);
251
1
        self.read()
252
1
    }
253
254
1
    pub fn read_view(&mut self, bytes: &'a [u8]) -> bp3d_proto::message::Result<usize> {
255
1
        self.buffer.set_bytes(bytes);
256
1
        self.read()
257
1
    }
258
259
41
    fn read(&mut self) -> bp3d_proto::message::Result<usize> {
260
41
        trace!({name=&*self.path_component.name}, "attempt read");
261
41
        if self.location.fixed {
  Branch (261:12): [True: 3, False: 1]
  Branch (261:12): [True: 13, False: 24]
262
16
            if self.buffer.len() < self.location.size {
  Branch (262:16): [True: 0, False: 3]
  Branch (262:16): [True: 0, False: 13]
263
0
                return Err(bp3d_proto::message::Error::Truncated)
264
16
            }
265
16
            if !self.buffer.flat.get() {
  Branch (265:16): [True: 3, False: 0]
  Branch (265:16): [True: 13, False: 0]
266
16
                self.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index(..self.location.size);
267
28
                for 
child12
in &mut self.children {
268
12
                    child.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index(child.location.offset as usize..child.location.offset as usize + child.location.size);
269
12
                    child.buffer.offset = self.buffer.offset + child.location.offset as usize;
270
12
                    child.read()
?0
;
271
                }
272
0
            }
273
16
            return Ok(self.location.size);
274
25
        }
275
25
        if let Some(
component12
) = self.component.take() {
  Branch (275:16): [True: 0, False: 1]
  Branch (275:16): [True: 12, False: 12]
276
12
            let mut tool = DiscoverTool::new(self.items.take(), std::mem::replace(&mut self.children, Vec::new()));
277
12
            if let Err(
e0
) = component.read(self, &mut tool) {
  Branch (277:20): [True: 0, False: 0]
  Branch (277:20): [True: 0, False: 12]
278
0
                self.component = Some(component);
279
0
                return Err(e);
280
12
            };
281
12
            self.component = Some(component);
282
12
            let (mut items, children) = tool.into_inner();
283
12
            if let Some(
items0
) = &mut items {
  Branch (283:20): [True: 0, False: 0]
  Branch (283:20): [True: 0, False: 12]
284
0
                let mut item_offset = 0;
285
0
                for (index, item) in items.iter_mut().enumerate() {
286
0
                    item.path_component.index.set(index as _);
287
0
                    if item.location.offset != -1 {
  Branch (287:24): [True: 0, False: 0]
  Branch (287:24): [True: 0, False: 0]
288
0
                        item_offset = item.location.offset;
289
0
                    }
290
0
                    if item_offset as usize >= self.buffer.len() {
  Branch (290:24): [True: 0, False: 0]
  Branch (290:24): [True: 0, False: 0]
291
0
                        return Err(bp3d_proto::message::Error::Truncated);
292
0
                    }
293
0
                    unsafe { item.buffer.unsafe_buffer.delete() };
294
0
                    item.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index((item_offset as usize)..);
295
                    // Again type inference is broken.
296
0
                    item.buffer.offset = self.buffer.offset + item_offset as usize;
297
0
                    let size = item.read()?;
298
0
                    if (item_offset as usize) + size > self.buffer.len() {
  Branch (298:24): [True: 0, False: 0]
  Branch (298:24): [True: 0, False: 0]
299
0
                        return Err(bp3d_proto::message::Error::Truncated);
300
0
                    }
301
0
                    item.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index((item_offset as usize)..(item_offset as usize) + size);
302
0
                    item_offset += size as isize;
303
                }
304
12
            }
305
12
            self.children = children;
306
12
            self.items = items;
307
13
        }
308
25
        let mut offset = self.location.size as isize;
309
46
        for 
child21
in &mut self.children {
310
21
            if child.location.offset != -1 {
  Branch (310:16): [True: 1, False: 0]
  Branch (310:16): [True: 0, False: 20]
311
1
                offset = child.location.offset;
312
20
            }
313
21
            if offset as usize >= self.buffer.len() {
  Branch (313:16): [True: 0, False: 1]
  Branch (313:16): [True: 0, False: 20]
314
0
                return Err(bp3d_proto::message::Error::Truncated);
315
21
            }
316
21
            unsafe { child.buffer.unsafe_buffer.delete() };
317
21
            child.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index((offset as usize)..);
318
            // Again type inference is broken.
319
21
            child.buffer.offset = self.buffer.offset + offset as usize;
320
21
            let size = child.read()
?0
;
321
21
            if (offset as usize) + size > self.buffer.len() {
  Branch (321:16): [True: 0, False: 1]
  Branch (321:16): [True: 0, False: 20]
322
0
                return Err(bp3d_proto::message::Error::Truncated);
323
21
            }
324
21
            child.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index((offset as usize)..(offset as usize) + size);
325
21
            trace!({name=&*child.path_component.name} {offset=child.buffer.offset}, "size: {}", size);
326
21
            offset += size as isize;
327
        }
328
25
        self.buffer.unsafe_buffer = self.buffer.unsafe_buffer.index(..offset as _);
329
25
        Ok(offset as _)
330
41
    }
331
332
27
    pub fn shape(&mut self) -> bp3d_proto::message::Result<()> {
333
27
        if let Some(
component12
) = self.component.take() {
  Branch (333:16): [True: 0, False: 2]
  Branch (333:16): [True: 12, False: 13]
334
12
            let items = self.items.take().unwrap_or_else(Vec::new);
335
12
            match component.shape(self, &items) {
336
0
                Err(e) => {
337
0
                    self.component = Some(component);
338
0
                    return Err(e);
339
                }
340
12
                _ => ()
341
            }
342
12
            self.component = Some(component);
343
12
            self.items = Some(items);
344
15
        } else if self.buffer.is_empty() && 
self.location.size > 06
{
  Branch (344:19): [True: 2, False: 0]
  Branch (344:45): [True: 1, False: 1]
  Branch (344:19): [True: 4, False: 9]
  Branch (344:45): [True: 2, False: 2]
345
3
            trace!({size=self.location.size}, "allocate empty buffer");
346
3
            self.buffer.unsafe_buffer = UnsafeBuffer::with_capacity(self.location.size);
347
12
        }
348
27
        if !self.location.fixed {
  Branch (348:12): [True: 1, False: 1]
  Branch (348:12): [True: 24, False: 1]
349
46
            for 
child21
in &mut self.children {
350
21
                child.shape()
?0
351
            }
352
2
        }
353
27
        trace!("buffer after shape: {:?}", self.buffer.as_bytes());
354
27
        if unsafe { &*self.path_component.parent.get() } .is_none() {
  Branch (354:12): [True: 1, False: 1]
  Branch (354:12): [True: 5, False: 20]
355
6
            self.flatten()
?0
;
356
21
        }
357
27
        Ok(())
358
27
    }
359
360
31
    fn flatten_internal(&mut self) {
361
31
        if self.children.len() > 0 {
  Branch (361:12): [True: 2, False: 2]
  Branch (361:12): [True: 9, False: 18]
362
11
            let mut v = Vec::with_capacity(self.buffer.len());
363
11
            let mut offset: usize = 0;
364
36
            for 
child25
in &mut self.children {
365
25
                if child.location.offset != -1 && 
child.location.offset7
> offset as _ {
  Branch (365:20): [True: 3, False: 0]
  Branch (365:51): [True: 0, False: 3]
  Branch (365:20): [True: 4, False: 18]
  Branch (365:51): [True: 3, False: 1]
366
3
                    // The compiler should be able to infer the type isize/usize but as always
367
3
                    // type-inference is broken.
368
3
                    let len = child.location.offset - offset as isize;
369
3
                    offset += v.write(&self.buffer.as_bytes()[..len as usize]).unwrap_or(0);
370
3
                    offset += child.location.offset as usize;
371
22
                }
372
25
                child.flatten_internal();
373
25
                trace!({name=&*child.path_component.name}, "child buffer: {:?}", child.buffer.as_bytes());
374
25
                offset += v.write(child.buffer.as_bytes()).unwrap_or(0);
375
            }
376
11
            trace!({name=&*self.path_component.name}, "master buffer: {:?}", v);
377
11
            unsafe { self.buffer.unsafe_buffer.copy(v.as_slice()) };
378
20
        }
379
31
    }
380
381
6
    fn flatten(&mut self) -> bp3d_proto::message::Result<()> {
382
6
        if self.buffer.flat.get() {
  Branch (382:12): [True: 0, False: 1]
  Branch (382:12): [True: 0, False: 5]
383
            // Nothing to do view is already flat!
384
0
            return Ok(())
385
6
        }
386
6
        self.flatten_internal();
387
6
        self.read()
?0
;
388
6
        self.buffer.flat.set(true);
389
6
        Ok(())
390
6
    }
391
392
0
    pub fn name(&self) -> &str {
393
0
        &self.path_component.name
394
0
    }
395
396
98
    pub fn get_path(&self) -> String {
397
98
        let mut v = Vec::new();
398
98
        let mut comp = &self.path_component;
399
98
        v.push(comp.name.clone());
400
244
        while let Some(
parent146
) = unsafe { &*comp.parent.get() } {
  Branch (400:19): [True: 14, False: 8]
  Branch (400:19): [True: 132, False: 90]
401
146
            comp = parent;
402
146
            let index = comp.index.get();
403
146
            if index != -1 {
  Branch (403:16): [True: 0, False: 14]
  Branch (403:16): [True: 0, False: 132]
404
0
                v.push(format!("[{}].", index) + &comp.name);
405
146
            } else {
406
146
                v.push(comp.name.clone());
407
146
            }
408
        }
409
98
        v.reverse();
410
98
        v.join(".")
411
98
    }
412
}
413
414
impl<'a, 'b> Index<&'a str> for BufferView<'b> {
415
    type Output = BufferView<'b>;
416
417
17
    fn index(&self, index: &'a str) -> &Self::Output {
418
17
        match self.get(index) {
419
17
            Some(view) => view,
420
0
            None => panic!("Unable to find view with path '{}'", index)
421
        }
422
17
    }
423
}
424
425
impl<'a, 'b> IndexMut<&'a str> for BufferView<'b> {
426
16
    fn index_mut(&mut self, index: &'a str) -> &mut Self::Output {
427
16
        match self.get_mut(index) {
428
16
            Some(view) => view,
429
0
            None => panic!("Unable to find view with path '{}'", index)
430
        }
431
16
    }
432
}
433
434
impl Drop for BufferView<'_> {
435
33
    fn drop(&mut self) {
436
33
        unsafe { self.buffer.unsafe_buffer.delete() };
437
33
    }
438
}